#include <iostream>
#include <string>
#include <vector>
#include <memory>
#include <unordered_map>
#include <functional>
#include <unistd.h>

using TaskFunc = std::function<void()>;
using ReleaseFunc = std::function<void()>;

//定时的任务类
class TimerTask
{
public:
    TimerTask(uint64_t id,uint32_t delay,const TaskFunc &cb)
    :_id(id),_timeout(delay),_task_cb(cb),_canceled(false)
    {}
    ~TimerTask()
    {
        //处理定时任务,如果没有被设置取消任务
        if(_canceled == false) _task_cb();//定时任务
        _release();//删除执行后的对象信息
    }
    void SetRelease(const ReleaseFunc& cb) { _release = cb; }//用于设置回调的release对象
    uint32_t DelayTime() { return _timeout;}
    void canceled() { _canceled = true; }
private:
    uint64_t _id; //定时器任务对象ID
    uint32_t _timeout;//定时任务的超时时间
    bool _canceled; //用于取消任务(true-表示被取消，false-表示不被取消)
    TaskFunc _task_cb;//定时器对象所需执行的定时任务
    ReleaseFunc _release;//用于删除TimeWheel中保存的定时器对象的信息
};

//定时器轮子(队列)
class TimerWheel
{
public:
    TimerWheel()
    :_capacity(60),_tick(0),_wheel(_capacity)
    {}
    ~TimerWheel()
    {}
    //添加定时任务
    void TimerAdd(uint64_t id,uint32_t delay,const TaskFunc &cb)
    {
        PtrTask pt(new TimerTask(id,delay,cb));//通过指针添加定时任务TimerTask
        pt->SetRelease(std::bind(&TimerWheel::RemoveTimer,this,id));
        int pos = (_tick + delay) % _capacity;
        _wheel[pos].push_back(pt);
        _timers[id] = WeakTask(pt);
    }
    //(刷新/延迟)定时任务
    void TimerRefresh(uint64_t id)
    {
        //通过保存的定时器对象的weak_ptr构造一个shared_ptr出来，添加到轮子当中
        auto it = _timers.find(id);
        if(it == _timers.end())
            return;//没有找到定时任务，没法刷新，直接退出
        PtrTask pt = it->second.lock();//lock获取weak_ptr管理对象对应的shared_ptr
        int delay = pt->DelayTime();
        int pos = (_tick + delay) % _capacity;
        _wheel[pos].push_back(pt);
    }
    //用于取消定时任务
    void Timerancel(uint64_t id)
    {
        auto it = _timers.find(id);
        if(it == _timers.end())
            return;
        PtrTask pt = it->second.lock();
        if(pt) pt->canceled();
    }
    //该函数应该一秒执行一次，相当于秒针向后走了一步
    void RunTimerTask()
    {
        _tick = (_tick + 1) % _capacity;
        _wheel[_tick].clear();//清除指定位置的数组，就会把数组中保存的所有管理定时器对象的shared_ptr释放掉
    }
private:
    //判断定时任务是否存在，根据id把该
    void RemoveTimer(uint64_t id)
    {
        auto it = _timers.find(id);
        if(it != _timers.end())
            _timers.erase(id);
    }
private:
    int _tick; //当前的秒针，走到哪里释放哪里，就执行哪里的任务
    int _capacity;//表示该定时器表盘的最大数量，也就是最大延时时间
    using WeakTask = std::weak_ptr<TimerTask>;//
    using PtrTask = std::shared_ptr<TimerTask>;//时间轮中的第二个参数，存放的是每个节点所对应的任务指针,可以通过该指针访问该任务(通过创建该指针添加任务)
    std::vector<std::vector<PtrTask>> _wheel;//时间轮当中的每一个节点都是一个vecto，每个节点当中存放一个PtrTask
    std::unordered_map<uint64_t,WeakTask> _timers;//用于通过定时器任务id，来获取到每一个任务
};

class Test
{
public:
    Test() { std::cout << "构造" << std::endl; }
    ~Test() { std::cout << "析构" << std::endl; }
};

void del_test(Test* tt)
{
    delete tt;
}

int main()
{
    TimerWheel tw;
    Test * t = new Test();
    tw.TimerAdd(1,5,std::bind(del_test,t));
    for(int i = 0; i < 5; i++)
    {
        sleep(1);
        tw.TimerRefresh(1);//刷新任务
        tw.RunTimerTask();//让轮子向后走
        std::cout << "刷新了定时任务,需要重新等待5s钟后才会执行销毁" << std::endl;
    }
    //tw.Timerancel(1);
    int i = 0;
    while(1)
    {
        sleep(1);
        std::cout << "I:[%d]--------------" << i++ << std::endl;
        tw.RunTimerTask();
        if(i = 2) tw.Timerancel(1);
    }

    return 0;
}